#include "Ball.h"
#include "Bucket.h"
#include "Scene/SceneManager.h"
#include "Resource/ResourceManager.h"

CBall::CBall()
{
	mObjectClassification = ObjectClassification_Ball;
	this->autorelease();
}
CBall::~CBall()
{
	
}
void CBall::Load(CCDictionary* ballDic)
{
	CCString* texPath = dynamic_cast<CCString*>(ballDic->objectForKey("path"));
	CCSprite* pBallSprite = CCSprite::create(texPath->getCString());
	this->addChild(pBallSprite, kBallZOrder, kBallTag);

	CCPoint point = CCPointFromString(ballDic->valueForKey("pos")->getCString());
	CCSize winSize = CCDirector::sharedDirector()->getWinSize();
	pBallSprite->setPosition(CCPoint(point.x*winSize.width,point.y*winSize.height));
	
	int color = ballDic->valueForKey("color")->intValue();
	mObjectColorType = color;

	// Define the dynamic body.
	b2BodyDef bodydef;
	bodydef.type = b2_dynamicBody;
	bodydef.position.Set(pBallSprite->getPositionX() / kPTM_RATIO, pBallSprite->getPositionY() / kPTM_RATIO);
	bodydef.userData = this;

	mBody = gBoxWorld->CreateBody(&bodydef);

	// Define another box shape for our dynamic body.
	b2CircleShape dynamicBallShape;
	dynamicBallShape.m_radius = pBallSprite->boundingBox().size.width * 0.5 / kPTM_RATIO;

	// Define the dynamic body fixture.
	b2FixtureDef fixtureDef;
	fixtureDef.shape = &dynamicBallShape;
	fixtureDef.density = 1.0f;
	fixtureDef.friction = 1.0f;
	fixtureDef.restitution = 0.4f;
	mBody->CreateFixture(&fixtureDef);

	//arrow
	CCSprite* arrowSprite = CCSprite::create(ResourceManager->GetTexture(Arrow));
	this->addChild(arrowSprite, this->getZOrder() + 1, kBallDirectionArrowTag);
	arrowSprite->setVisible(false);

	//shoot
	CCSprite* circleSprite = CCSprite::create(ResourceManager->GetTexture(Shoot));
	this->addChild(circleSprite, this->getZOrder() + 1, kShootCircleTag);
	circleSprite->setVisible(false);
	float scale = MaxRangeRadiusForShoot * 2 / circleSprite->getContentSize().width;
	circleSprite->setScale(scale);

	CCSprite* rangeSprite = CCSprite::create(ResourceManager->GetTexture(Range));
	this->addChild(rangeSprite, this->getZOrder() + 1, kShootRangeTag);
	rangeSprite->setOpacity(100.0f);
	rangeSprite->setVisible(false);

	//aim
	for (int i=0; i<kAimSpriteTotalNumber; ++i)
	{
		CCSprite* pAimSprite = CCSprite::create(ResourceManager->GetTexture(Aim));
		this->addChild(pAimSprite, this->getZOrder() + 1);
		pAimSprite->setVisible(false);
		pAimSprite->setScale(0.2f);
		mAimSpriteList.push_back(pAimSprite);
	}


}
void CBall::onEnter()
{
	CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, kBallTouchPriority, false);
	this->scheduleUpdate();
	CCNode::onEnter();
}
void CBall::update(float dt)
{
	if(BallBingoInBucket == mBallState)
	{
		SceneManager->GetLayer(GameScene)->removeChild(this,true);
		gBoxWorld->DestroyBody(mBody);
		return;
	}
	b2Vec2 ballSpeed = mBody->GetLinearVelocity();
	if(BallShootByBucket == mBallState &&
		(fabs(ballSpeed.x) > kStillSpeed || fabs(ballSpeed.y) > kStillSpeed))
	{
		mBallState = BallStateNone;
	}
	if (mBody)
	{
		CCSprite* arrowSprite = (CCSprite* )this->getChildByTag(kBallDirectionArrowTag);

		if (mBallState == BallStateMove &&
			this->getChildByTag(kBallTag) &&
			arrowSprite)
		{
			arrowSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());

			if (mBody)
			{
				b2Vec2 ballVelocity = mBody->GetLinearVelocity();
				float newRotation = -1 * CC_RADIANS_TO_DEGREES( ccpToAngle(CCPointMake(ballVelocity.x, ballVelocity.y)) );
				arrowSprite->setRotation( newRotation);
			}
			arrowSprite->setVisible(true);
		}

		CCSprite* circleSprite = (CCSprite*)this->getChildByTag(kShootCircleTag);
		if (mBallState == BallStateShoot &&
			this->getChildByTag(kBallTag) &&
			circleSprite)
		{
			circleSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());
			circleSprite->setVisible(true);
		}

		CCSprite* shootRangeSprite = (CCSprite*)this->getChildByTag(kShootRangeTag);
		if (mBallState == BallStateShoot &&
			shootRangeSprite &&
			shootRangeSprite->isVisible() == true)
		{
			shootRangeSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());
		}
	}
}
bool CBall::_isTouchPointInBall(CCTouch* pTouchPos)
{
	CCPoint touchPos = pTouchPos->locationInView();
	touchPos = CCDirector::sharedDirector()->convertToGL(touchPos);

	if (this->getChildByTag(kBallTag))
	{
		return CCRect::CCRectContainsPoint(this->getChildByTag(kBallTag)->boundingBox(), touchPos);
	}
	return false;
}
bool CBall::ccTouchBegan(CCTouch* pTouch, CCEvent* pEvent)
{
	if (BallStateShoot == mBallState)
	{
		return true;
	}

	if (_isTouchPointInBall(pTouch))
	{
		mBallState = BallStateSelected;

		return true;
	}
	mBallState = BallStateNone;
	return true;
}
void CBall::ccTouchMoved(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
	CCPoint touchPos = pTouch->locationInView();
	touchPos = CCDirector::sharedDirector()->convertToGL(touchPos);

	if (BallStateSelected == mBallState ||
		BallStateMove == mBallState)
	{
		mBallState = BallStateMove;

		touchPos.x = touchPos.x / kPTM_RATIO;

		float distance = touchPos.x - mBody->GetPosition().x;
		distance = distance > 2.0f ? 2.0f : distance;
		b2Vec2 force = b2Vec2(distance * MaxForceForMove, 0.0f);
		mBody->ApplyForce(force, mBody->GetWorldCenter());

		return;
	}

	if (BallStateShoot == mBallState)
	{
		CCSprite* shootRangeSprite = (CCSprite*)this->getChildByTag(kShootRangeTag);
		if (shootRangeSprite)
		{
			CCPoint ballPos = CCPointMake( mBody->GetPosition().x * kPTM_RATIO,
				mBody->GetPosition().y * kPTM_RATIO);
			float distanceToBall = ccpDistance(touchPos, ballPos);
			distanceToBall = distanceToBall > MaxRangeRadiusForShoot ? MaxRangeRadiusForShoot : distanceToBall;
			float scale = distanceToBall * 2.0f / shootRangeSprite->getContentSize().width;
			shootRangeSprite->setScale(scale);
			shootRangeSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());
			shootRangeSprite->setVisible(true);

			CCPoint direction = ccpNormalize(CCPointMake(touchPos.x - ballPos.x,touchPos.y - ballPos.y));
			distanceToBall = distanceToBall > MaxRangeRadiusForShoot ? MaxRangeRadiusForShoot : distanceToBall;
			b2Vec2 force = b2Vec2(direction.x * distanceToBall * MaxForceForShoot / MaxRangeRadiusForShoot,
				direction.y * distanceToBall * MaxForceForShoot / MaxRangeRadiusForShoot);

			float timeSpace = 0.06f;
			int index = 1;
			b2Vec2 gravity = b2Vec2(Box2DGravity.x, Box2DGravity.y);
			
			for(list<CCSprite*>::iterator iter=mAimSpriteList.begin();
				iter != mAimSpriteList.end();
				++iter)
			{
				CCSprite* aimSprite = *iter;
				float dt = index * timeSpace;
				if (aimSprite)
				{
					aimSprite->setPosition(this->getChildByTag(kBallTag)->getPosition());
					aimSprite->setVisible(true);
					aimSprite->setOpacity(255.0f - 255.0f * index / (kAimSpriteTotalNumber + 1));
					aimSprite->setPositionX(aimSprite->getPositionX() + kPTM_RATIO * dt * force.x / mBody->GetMass());
					aimSprite->setPositionY(aimSprite->getPositionY() + kPTM_RATIO * dt * force.y / mBody->GetMass() + kPTM_RATIO * 0.5 * gravity.y * dt * dt);
				}

				index++;
			}
		}
	}
}


void CBall::ccTouchEnded(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent)
{
	if (this->getChildByTag(kBallDirectionArrowTag))
	{
		this->getChildByTag(kBallDirectionArrowTag)->setVisible(false);
		mBody->ApplyForce(b2Vec2(0.0f, 0.0f), mBody->GetWorldCenter());
	}


	if (BallStateMove == mBallState)
	{
		mBallState = BallStateNone;
	}

	if (BallStateShoot == mBallState)
	{
		mBallState = BallStateNone;

		if (this->getChildByTag(kShootCircleTag))
		{
			this->getChildByTag(kShootCircleTag)->setVisible(false);
		}
		if (this->getChildByTag(kShootRangeTag))
		{
			this->getChildByTag(kShootRangeTag)->setVisible(false);
		}
		
		for(list<CCSprite*>::iterator iter=mAimSpriteList.begin();
			iter != mAimSpriteList.end();
			++iter)
		{
			if (*iter)
			{
				((CCSprite*)*iter)->setVisible(false);
			}
		}

		CCPoint touchPos = pTouch->locationInView();
		touchPos = CCDirector::sharedDirector()->convertToGL(touchPos);
		CCPoint ballPos = CCPointMake(mBody->GetPosition().x * kPTM_RATIO,
			mBody->GetPosition().y * kPTM_RATIO);
		float distance = ccpDistance(touchPos, ballPos);
		CCPoint direction = ccpNormalize(CCPointMake(touchPos.x - ballPos.x,
			touchPos.y - ballPos.y));
		distance = distance > MaxRangeRadiusForShoot ? MaxRangeRadiusForShoot : distance;
		b2Vec2 force = b2Vec2(direction.x * distance * MaxForceForShoot / MaxRangeRadiusForShoot,
			direction.y * distance * MaxForceForShoot / MaxRangeRadiusForShoot);

		mBody->ApplyLinearImpulse(force, mBody->GetWorldCenter());
	}

	if (BallStateSelected == mBallState)
	{
		if (this->_isTouchPointInBall(pTouch))
		{
			mBallState = BallStateShoot;
		}
		else
		{
			mBallState = BallStateNone;
		}
	}
}


void CBall::setPosition(const cocos2d::CCPoint &newPosition)
{
	if (this->getChildByTag(kBallTag))
	{
		this->getChildByTag(kBallTag)->setPosition(newPosition);
	}
}

void CBall::setScale(float scale)
{
	if (this->getChildByTag(kBallTag))
	{
		this->getChildByTag(kBallTag)->setScale(scale);
	}
}
void CBall::setRotation(float fRotation)
{
	if (this->getChildByTag(kBallTag))
	{
		this->getChildByTag(kBallTag)->setRotation(fRotation);
	}
}
void CBall::ShootByBucket(CBucket* bucket)
{
	b2Vec2 force;
	CCPoint point = ccpRotateByAngle(CCPoint(0,1),CCPoint(0,0),bucket->GetBody()->GetAngle());
	force.Set(BucketForce*point.x,BucketForce*point.y);
	mBody->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
	mBody->ApplyForce(force, mBody->GetWorldCenter());
	mBallState = BallShootByBucket;
}
void CBall::BingoInBucket()
{
	//stop the ball
	mBody->SetLinearVelocity(b2Vec2(0.0f, 0.0f));
	mBallState = BallBingoInBucket;
	mBody->SetUserData(NULL);
	
}
